using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using StudentVideo.Common.Attributes;
using StudentVideo.Common.Constants;
using StudentVideo.Common.Exceptions;
using StudentVideo.Data;
using StudentVideo.Data.Entities;
using StudentVideo.Helper;
using StudentVideo.Shared.Dtos.Login;
using StudentVideo.Shared.Enums;
using StudentVideo.Utils;
using StudentVideo.Common.Models;

namespace StudentVideo.Controllers;

/// <summary>
/// 登录
/// </summary>
/// <param name="context"></param>
/// <param name="jwtHelper"></param>
[ApiController]
[Route("api/[controller]/[action]")]
public class LoginController(AppDbContext context, JwtHelper jwtHelper): ControllerBase {
   private readonly AppDbContext _context = context;
   private readonly JwtHelper _jwtHelper = jwtHelper;

   /// <summary>
   /// 用户登录
   /// </summary>
   /// <param name="body"></param>
   /// <returns></returns>
   [HttpPost]
   [AllowAnonymous]
   public async Task<LoginResult> Admin([FromBody] LoginRequest body) {
      var mapping = new QueryMapping<UserEntity, LoginRequest>()
         .AddMapping(d => d.Account, s => s.Username);

      var query = mapping.BuildQuery(_context.Users.AsQueryable(), body);

      var user = await query
         .AsNoTracking()
         .FirstOrDefaultAsync()
         ?? throw new HttpException(HttpErrorMessage.USER_NOT_EXIST);

      if (!PasswordHasher.VerifyPassword(body.Pwd, user.Salt, user.Password))
         throw new HttpException(HttpErrorMessage.USER_PWD_ERROR);

      var token = _jwtHelper.GenerateJwtToken(user.Id, UserRangeEnum.Internal);

      return new() {
         Token = token
      };
   }

   /// <summary>
   /// 客户端登录
   /// </summary>
   /// <param name="body"></param>
   /// <returns></returns>
   /// <exception cref="HttpException"></exception>
   [HttpPost]
   [AllowAnonymous]
   public async Task<LoginResult> Student([FromBody] LoginRequest body) {

      var target = await _context.Students
         .AsNoTracking()
         .Where(e => e.StudentId == body.Account || e.IdCard == body.Account)
         .FirstOrDefaultAsync()
         ?? throw new HttpException(HttpErrorMessage.ACCOUNT_ERROR);

      if (PasswordHasher.VerifyPassword(body.Pwd, target.Salt, target.Password))
         throw new HttpException(HttpErrorMessage.USER_PWD_ERROR);

      var token = _jwtHelper.GenerateJwtToken(target.Id, UserRangeEnum.External);

      return new() {
         Token = token
      };
   }

   /// <summary>
   /// 刷新 token
   /// </summary>
   /// <param name="user"></param>
   [HttpPost]
   public LoginResult ReloadToken([FromCurrentUser] CurrentUser user) {
      var token = _jwtHelper.GenerateJwtToken(user.UserId, user.UserRange);

      return new() { Token = token };
   }
}
